#!/usr/bin/env python

import json
import model
import restclient
import sqlalchemy

import sqlalchemy.orm as sao

import datetime
from model import DeclarativeBase

__all__ = ['SearchHost']


class SearchHost(DeclarativeBase):
    """
    Store information about the progress of downloaded data from host of each
    search. Because data downloading sometimes stopped mysteriously.

    Attributes:
        - search_id: An integer for search primary key.
        - host_id: An integer for host foreign key.
        - last_page: An integer indicating last page downloaded. Updating should
            begin from this page, unless stated otherwise.
        - last_update: A date time when last page reached. Should be updated
            only when last page retrieved successfully.
    """

    __tablename__ = 'searches_hosts'

    id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True)
    """
    The primary key.

    @type: int
    """

    search_id = sqlalchemy.Column(sqlalchemy.Integer,
                                  sqlalchemy.ForeignKey("searches.id"),
                                  nullable=False, index=True)
    """
    Search primary key.

    @type: int
    """

    host_id = sqlalchemy.Column(sqlalchemy.Integer,
                                sqlalchemy.ForeignKey("hosts.id"),
                                nullable=False,
                                index=True)
    """
    Host primary key.

    @type: int
    """

    last_page = sqlalchemy.Column(sqlalchemy.Integer, default=1)
    """
    Last page of post retrieved successfully.

    @type: int
    """

    last_update = sqlalchemy.Column(sqlalchemy.DateTime)
    """
    Date time when post data last updated. This value should be updated only
    when last page of post retrieved successfully.

    @type: datetime
    """

    search = sao.relationship('Search', uselist=False,
                              backref=sao.backref('search_hosts'))
    """
    The Search instance of search_id.

    @type: Search
    """

    host = sao.relationship('Host', uselist=False,
                            backref=sao.backref('search_hosts'))
    """
    The Host instance of host_id.

    @type: Host
    """

    def download(self):
        """
        Download post data from host.

        If number of tuple element is less than 100 then that means last
        page is reached. You should stop advanced to next page.

        @rtype: tuple
        @return: A tuple of response header and collection of Post object.
        """

        if self.host.type == model.Host.TYPE_GELBOORU:
            return self._download_xml()

        return self._download_json()

    def mock_download(self, tag):
        """
        Mock download post data from host.

        This method will read data from folder data/posts/{tag}.json

        @param tag: Json filename to read.
        @type tag: str

        @rtype: tuple
        @return: A tuple of response header and collection of Post object.
        """

        import os

        headers = {'status': 200}
        path = os.path.join('data', 'posts', u'{0:s}.json'.format(tag))
        data = json.load(open(path))
        posts = []
        for datum in data:
            post = model.Post(self.host, self.search)
            post.load(datum)
            posts.append(post)
        return headers, posts

    def _download_json(self):
        """
        Download post data from host in JSON format.

        @rtype: tuple
        @return: A tuple of response header and collection of Post object.
        """

        url = self.host.create_url(self.last_page, self.search.value)
        responses = restclient.GET(url, async=False, resp=True)
        responses[0]['status'] = int(responses[0]['status'])
        posts = json.loads(responses[1])
        header = responses[0]
        data = []
        if header['status'] == 200:
            for post in posts:
                datum = model.Post(self.host, self.search)
                if datum.load(post):
                    data.append(datum)
                else:
                    data.append(None)

        return header, data

    def _download_xml(self):
        """
        Download post data from host in XML format.

        @see: self.download
        @rtype: tuple
        """

        url = self.host.create_url(self.last_page, self.search.value, 'xml')
        return url

    @property
    def should_refresh(self):
        """
        Check last_update, if the last_update is None or a month ago or older,
        then it should be refreshed.

        @rtype: bool
        @return: Whether post data should be checked for new data or not. Post
            data should be downloaded from last_page.
        """

        if not self.last_update:
            return True

        one_month_ago = datetime.datetime.now() - datetime.timedelta(weeks=4)
        if self.last_update < one_month_ago:
            return True

        return False
